﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
using System.Diagnostics;
using jaysJourney_v01.States;
using jaysJourney_v01.Common;

namespace jaysJourney_v01.Utils
{
    class InputField : Button
    {
        /**
         * MEMBER VARIABLES
         * */

        // From Parent

        private ContentManager content;

        // Common

        private int maxLength;
        private String placeHolder;
        private bool activeInput;

        private bool isSecure;
        private bool isEmail;

        private bool isRightAlt;
        private bool isUpper;

        private Texture2D textureAc;

        // Input

        private Keys[] lastPressedKeys;
        private String textBuffer;

        // Input Filter

        private static List<Keys> INCLUDES = new List<Keys>()
        {
            Keys.A, Keys.B, Keys.C, Keys.D, Keys.E, Keys.F, Keys.G, Keys.H, Keys.I, Keys.J, Keys.K,
            Keys.L, Keys.M, Keys.N, Keys.O, Keys.P, Keys.Q, Keys.R, Keys.S, Keys.T, Keys.U, Keys.V,
            Keys.W, Keys.X, Keys.Y, Keys.Z, Keys.D0, Keys.D1, Keys.D2, Keys.D3, Keys.D4, Keys.D5, Keys.D6,
            Keys.D7, Keys.D8, Keys.D9
        };

        /**
         * METHODS
         * */

        // Constructor

        public InputField(State parentState, String name, Vector2 pos, String bgImg, String bgImgHover, String bgImgAc, int maxLength, bool isActive, bool isSecure, bool isEmail) : base(parentState, name, bgImg, bgImgHover, (int)pos.X, (int)pos.Y, Color.White, isActive, true)
        {
            this.content = parentState.getGame().Content;
            this.maxLength = maxLength;
            this.placeHolder = name;
            this.textBuffer = name;
            this.isSecure = isSecure;
            this.isEmail = isEmail;

            this.lastPressedKeys = new Keys[0];
            this.textFont = content.Load<SpriteFont>(@"Fonts\Segoe UI Mono");

            this.textureAc = content.Load<Texture2D>(bgImgAc);
            if (isActive) this.activeInput = true;
        }

        // MAIN UPDATE

        public new void update()
        {
            if (this.activeInput)
            {
                if (this.textBuffer == this.placeHolder) this.textBuffer = "";

                KeyboardState kbState = Keyboard.GetState();
                Keys[] pressedKeys = kbState.GetPressedKeys();

                //check if any of the previous update's keys are no longer pressed
                foreach (Keys key in lastPressedKeys)
                {
                    if (!pressedKeys.Contains(key)) OnKeyUp(key);
                }

                //check if the currently pressed keys were already pressed
                foreach (Keys key in pressedKeys)
                {
                    if (!lastPressedKeys.Contains(key)) OnKeyDown(key);
                }

                //save the currently pressed keys so we can compare on the next update
                lastPressedKeys = pressedKeys;
            }

            base.update();
        }

        // MAIN DRAW

        public new void draw()
        {
            // draw bg
            if(this.activeInput) parentSpriteBatch.Draw(this.textureAc, position, Color.White);
            else base.draw();

            // draw text
            if(!base.getActive() && !this.activeInput && this.textBuffer.Length == 0) this.textBuffer = this.placeHolder;
            if (this.isSecure && this.textBuffer != this.placeHolder)
            {
                String secure = "";
                while (secure.Length != textBuffer.Length) secure += "X";
                this.drawName(Color.Black, secure);
                //parentSpriteBatch.DrawString(textFont, secure, new Vector2(base.position.X + 10, base.position.Y + (base.passTexture.Height / 2 ) - (textFont.LineSpacing / 2)), Color.Black, 0, new Vector2(0, 0), 1.0f, SpriteEffects.None, 1f);
            }
            else
            {
                this.drawName(Color.Black, textBuffer);
                //parentSpriteBatch.DrawString(textFont, textBuffer, new Vector2(base.position.X + 10, base.position.Y + (base.passTexture.Height / 2) - (textFont.LineSpacing / 2)), Color.Black, 0, new Vector2(0, 0), 1.0f, SpriteEffects.None, 1f);
            }
        }

        // onKeyDown

        private void OnKeyDown(Keys key)
        {
            switch (key)
            {
                case Keys.RightAlt:
                    this.isRightAlt = true;
                    break;
                case Keys.LeftShift: case Keys.RightShift:
                    this.isUpper = true;
                    break;
                case Keys.Back:
                    if (textBuffer.Length > 0) textBuffer = textBuffer.Remove(textBuffer.Length - 1, 1);
                    break;
                case Keys.Space:
                    if(textBuffer.Length < this.maxLength) textBuffer = textBuffer.Insert(textBuffer.Length, " ");
                    break;
                case Keys.OemPeriod:
                    if (textBuffer.Length < this.maxLength && this.isEmail) textBuffer += convertInput(key.ToString());
                    break;
                default:
                    if(textBuffer.Length < this.maxLength && isInclude(key)) textBuffer += convertInput(key.ToString());
                    break;
            }
        }

        // onKeyUp

        private void OnKeyUp(Keys key)
        {
            if (key.Equals(Keys.RightAlt)) this.isRightAlt = false;
            if (key.Equals(Keys.LeftShift) || key.Equals(Keys.RightShift)) this.isUpper = false;
        }

        // only first uppercase

        private string upperFirst(string s)
        {
            // Check for empty string.
            if (string.IsNullOrEmpty(s)) return string.Empty;

            // lower everything
            s = s.ToLower();

            StringBuilder sb = new StringBuilder(s);

            // upper every first Letter after space
            for (int i = 0; i < sb.Length; i++)
            {
                if (i == 0 || sb[i - 1].Equals(' ')) sb[i] = char.ToUpper(sb[i]);
            }

            // Return char and concat substring.
            return sb.ToString();
        }

        // check excludeable
        private bool isInclude(Keys key)
        {
            foreach (Keys keys in INCLUDES)
            {
                if (keys == key) return true;
            }
            return false;
        }

        // convert input
        private String convertInput(String inp)
        {
            String output;
            String input = inp.ToLower();

            switch (input)
            {
                case "d1": output = "1"; break;
                case "d2": output = "2"; break;
                case "d3": output = "3"; break;
                case "d4": output = "4"; break;
                case "d5": output = "5"; break;
                case "d6": output = "6"; break;
                case "d7": output = "7"; break;
                case "d8": output = "8"; break;
                case "d9": output = "9"; break;
                case "d0": output = "0"; break;
                case "q":
                    if (this.isRightAlt && this.isEmail) output = "@";
                    else if (this.isUpper) output = input.ToUpper();
                    else output = input;
                    break;
                case "oemperiod": output = "."; break;
                default:
                    if (this.isUpper) output = input.ToUpper();
                    else output = input;
                    break;
            }

            return output;
        }

        // get content
        public String getContent()
        {
            return this.textBuffer;
        }

        // set activeInput
        public void setActiveInput(bool flag)
        {
            this.activeInput = flag;
        }

        // get activeInput
        public bool getActiveInput()
        {
            return this.activeInput;
        }

        // reset content
        public void resetContent()
        {
            this.textBuffer = this.placeHolder;
        }
    }
}